package main

import (
    "syscall"
	"unsafe"
    "fmt"
    "crypto/rand"
)

var moduser32 = syscall.NewLazyDLL("user32.dll")
var procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
var procDefWindowProc = moduser32.NewProc("DefWindowProcW")
var procRegisterClassEx = moduser32.NewProc("RegisterClassExW")
var procCreateWindowEx = moduser32.NewProc("CreateWindowExW")
var procShowWindow = moduser32.NewProc("ShowWindow")
var procGetMessage = moduser32.NewProc("GetMessageW")
var procTranslateAccelerator = moduser32.NewProc("TranslateAccelerator")
var procTranslateMessage = moduser32.NewProc("TranslateMessage")
var procDispatchMessage = moduser32.NewProc("DispatchMessageW")
var procLoadCursor = moduser32.NewProc("LoadCursorW")
var modkernel32 = syscall.NewLazyDLL("kernel32.dll")
const WM_DESTROY = 2
const COLOR_WINDOW = 5
const CS_HREDRAW = 0x00000002
const CS_VREDRAW = 0x00000001
const CS_DBLCLKS = 0x00000008
const CW_USEDEFAULT = ^0x7fffffff
const SW_SHOW = 5
const IDI_APPLICATION = 32512
const WS_OVERLAPPEDWINDOW = 0X00000000 | 0X00C00000 | 0X00080000 | 0X00040000 | 0X00020000 | 0X00010000
type HINSTANCE uintptr
type HWND uintptr
type HICON uintptr
type HCURSOR uintptr
type HBRUSH uintptr
type ATOM uint16
type HMENU uintptr
type BOOL int32

type POINT struct {
	X, Y int32
}

func PostQuitMessageW32(exitCode int) {
	procPostQuitMessage.Call(
		uintptr(exitCode))
}

func DefWindowProcW32(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
	ret, _, _ := procDefWindowProc.Call(
		uintptr(hwnd),
		uintptr(msg),
		wParam,
		lParam)

	return ret
}

func RegisterClassExW32(wndClassEx *WNDCLASSEX) ATOM {
	ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx)))
	return ATOM(ret)
}

func CreateWindowExW32(exStyle uint, className, windowName *uint16,
	style uint, x, y, width, height int, parent HWND, menu HMENU,
	instance HINSTANCE, param unsafe.Pointer) HWND {
	ret, _, _ := procCreateWindowEx.Call(
		uintptr(exStyle),
		uintptr(unsafe.Pointer(className)),
		uintptr(unsafe.Pointer(windowName)),
		uintptr(style),
		uintptr(x),
		uintptr(y),
		uintptr(width),
		uintptr(height),
		uintptr(parent),
		uintptr(menu),
		uintptr(instance),
		uintptr(param))

	return HWND(ret)
}

func ShowWindowW32(hwnd HWND, cmdshow int) bool {
	ret, _, _ := procShowWindow.Call(
		uintptr(hwnd),
		uintptr(cmdshow))

	return ret != 0
}

func GetMessageW32(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int {
	ret, _, _ := procGetMessage.Call(
		uintptr(unsafe.Pointer(msg)),
		uintptr(hwnd),
		uintptr(msgFilterMin),
		uintptr(msgFilterMax))

	return int(ret)
}

func TranslateAccelerator32(hwnd HWND, msg *MSG) bool {
	ret, _, _ := procTranslateAccelerator.Call(
        uintptr(hwnd),
        uintptr(0),
		uintptr(unsafe.Pointer(msg)))
    return ret != 0
}

func TranslateMessageW32(msg *MSG) bool {
	ret, _, _ := procTranslateMessage.Call(
		uintptr(unsafe.Pointer(msg)))

	return ret != 0
}

func DispatchMessageW32(msg *MSG) uintptr {
	ret, _, _ := procDispatchMessage.Call(
		uintptr(unsafe.Pointer(msg)))
	return ret
}

func LoadCursorW32(instance HINSTANCE, cursorName *uint16) HCURSOR {
	ret, _, _ := procLoadCursor.Call(
		uintptr(instance),
		uintptr(unsafe.Pointer(cursorName)))

	return HCURSOR(ret)

}

type WNDCLASSEX struct {
	Size       uint32
	Style      uint32
	WndProc    uintptr
	ClsExtra   int32
	WndExtra   int32
	Instance   HINSTANCE
	Icon       HICON
	Cursor     HCURSOR
	Background HBRUSH
	MenuName   *uint16
	ClassName  *uint16
	IconSm     HICON
}

type MSG struct {
	Hwnd    HWND
	Message uint32
	WParam  uintptr
	LParam  uintptr
	Time    uint32
	Pt      POINT
}

/*
* 消息循环
*/
func WndProc(hwnd HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
    if msg == WM_DESTROY{
        PostQuitMessageW32(0)
        return 1
    }
    return DefWindowProcW32(hwnd, msg, wParam, lParam)
}

func main() {
    title := "MyWindow"
    var wc WNDCLASSEX
    wc.Size = uint32(unsafe.Sizeof(wc))
    wc.WndProc = syscall.NewCallback(WndProc)
    wc.Cursor = LoadCursorW32(0, (*uint16)(unsafe.Pointer(uintptr(IDI_APPLICATION))))
    wc.Background = COLOR_WINDOW + 1
    b := make([]byte, 16)
    rand.Read(b)
    uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
    wc.ClassName = syscall.StringToUTF16Ptr(uuid)
    wc.Style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS
    RegisterClassExW32(&wc)
    hWnd := CreateWindowExW32(0, syscall.StringToUTF16Ptr(uuid), syscall.StringToUTF16Ptr(title),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        0, 0, 0, nil)
    ShowWindowW32(hWnd, SW_SHOW)
    var msg MSG
    for {
		ret := GetMessageW32(&msg, 0, 0, 0)
		fmt.Println(ret)
        if ret > 0 {
            if !TranslateAccelerator32(msg.Hwnd, &msg){
                TranslateMessageW32(&msg)
                DispatchMessageW32(&msg)
            }
        } else {
            break
        }
    }
}